#!/usr/bin/env python3
# 订阅 /audio_msg，打印其中的 "text" 字段
import json
import re
import sys
import os
import importlib.util
import time
import subprocess
import threading

# 导入 ROS2 相关库
import rclpy
from rclpy.node import Node
from std_msgs.msg import String

# 导入同目录下的模块
current_dir = os.path.dirname(os.path.abspath(__file__))

# 导入 ollama_chat 模块
ollama_chat_path = os.path.join(current_dir, 'ollama_chat.py')
spec = importlib.util.spec_from_file_location("ollama_chat", ollama_chat_path)
ollama_chat = importlib.util.module_from_spec(spec)
spec.loader.exec_module(ollama_chat)
chat_with_ollama = ollama_chat.chat_with_ollama

# 导入 floor_parse 模块
floor_parse_path = os.path.join(current_dir, 'floor_parse.py')
spec = importlib.util.spec_from_file_location("floor_parse", floor_parse_path)
floor_parse = importlib.util.module_from_spec(spec)
spec.loader.exec_module(floor_parse)
parse_floors = floor_parse.parse_floors

# TTS 脚本路径
tts_script_path = os.path.join(current_dir, 'g1_audio_tts.py')


class TextPrinter(Node):
    def __init__(self, network_interface='eth0', default_mode='chat'):
        super().__init__('text_printer')
        self.sub = self.create_subscription(
            String, '/audio_msg', self.callback, 10)
        self.processing = False  # 标记是否正在处理请求
        self.network_interface = network_interface  # 存储网络接口名称
        self.tts_process = None  # 存储TTS进程
        self.use_ollama_llm=False
        
        # 模式标志 - 支持通过变量选择默认模式
        self.default_mode = default_mode  # 默认模式: 'chat' 或 'elevator'
        if default_mode == 'elevator':
            self.flag_chat = 0  # 对话模式标志
            self.flag_elevator = 1  # 电梯模式标志
        else:  # 默认为对话模式
            self.flag_chat = 1 # 对话模式标志，默认为1
            self.flag_elevator = 0  # 电梯模式标志，默认为0
        
        # 电梯模式相关变量
        self.elevator_timespan = 5.0  # 电梯模式收集楼层的时间窗口（秒）
        self.floor_arr_set = set()  # 用于去重的楼层集合
        self.elevator_timer = None  # 电梯计时器
        self.elevator_timer_active = False  # 电梯计时器是否激活
        
        # 楼层解析默认参数
        self.default_min_floor = 1  # 默认最小楼层
        self.default_max_floor = 3  # 默认最大楼层
        
        # 启动时进入默认模式并提示
        self.initial_chat_announced = False  # 标记是否已播报过初始对话模式
        self.initial_elevator_announced = False  # 标记是否已播报过电梯模式
        self.get_logger().info(f"默认进入{self.default_mode}模式")
        
        if self.default_mode == 'elevator':
            self.speak_text("电梯模式，请说出您想去的楼层（支持1层到3层）。")
            self.initial_elevator_announced = True
            # 启动初始计时器
            self.elevator_timer_active = True
            self.elevator_timer = threading.Timer(self.elevator_timespan, self._handle_elevator_timeout)
            self.elevator_timer.start()
            self.get_logger().info(f"启动初始电梯计时器，{self.elevator_timespan}秒后处理")
        else:
            self.speak_text("对话模式，请提问。您可选择电梯模式。")
            self.initial_chat_announced = True
        
    def speak_text(self, text, priority=0):
        """
        使用单独的进程执行TTS，避免与ROS2冲突
        """
        def run_tts_process():
            try:
                # 使用子进程调用g1_audio_tts.py脚本
                cmd = [sys.executable, tts_script_path, text, self.network_interface]
                self.get_logger().info(f"执行TTS命令: {' '.join(cmd)}")
                
                # 创建子进程
                process = subprocess.Popen(
                    cmd,
                    stdout=subprocess.PIPE,
                    stderr=subprocess.PIPE,
                    text=True
                )
                
                # 获取输出
                stdout, stderr = process.communicate()
                
                # 检查结果
                if process.returncode == 0:
                    self.get_logger().info("TTS执行成功")
                    return True
                else:
                    self.get_logger().error(f"TTS执行失败: {stderr}")
                    return False
                    
            except Exception as e:
                self.get_logger().error(f"TTS进程创建失败: {str(e)}")
                return False
        
        # 在新线程中执行TTS，避免阻塞ROS2节点
        tts_thread = threading.Thread(target=run_tts_process)
        tts_thread.daemon = True  # 设置为守护线程，主程序退出时自动结束
        tts_thread.start()
        
        return True  # 返回启动状态，实际TTS结果在线程中处理

    def is_valid_text(self,text,str_valid_ratio=0.6):
        """
        判断文本是否为有效文本（中文、中英文混合、纯英文或包含数字，且这些有效字符占比超过60%）
        
        参数:
            text: 输入文本
            
        返回:
            bool: 是否为有效文本
        """
        if not text or text.strip() == "":
            return False
            
        # 计算中文、英文和数字字符数量
        chinese_pattern = re.compile(r'[\u4e00-\u9fff]')
        english_pattern = re.compile(r'[a-zA-Z]')
        digit_pattern = re.compile(r'[0-9]')
        
        chinese_chars = chinese_pattern.findall(text)
        english_chars = english_pattern.findall(text)
        digit_chars = digit_pattern.findall(text)
        
        valid_chars_count = len(chinese_chars) + len(english_chars) + len(digit_chars)
        total_chars = len(text.strip())
        
        if total_chars == 0:
            return False
            
        valid_ratio = valid_chars_count / total_chars
        
        # 如果有效字符（中文、英文、数字）占比超过60%，则认为是有效文本
        return valid_ratio >= str_valid_ratio
    
    def _handle_elevator_timeout(self):
        """
        处理电梯计时器超时事件
        """
        self.elevator_timer_active = False
        
        if self.floor_arr_set:
            # 将集合转换为排序后的列表
            final_floors = sorted(list(self.floor_arr_set))
            floors_str = "层、".join(map(str, final_floors))
            response = f"准备为您按{floors_str}层的电梯"
            
            self.get_logger().info(f"电梯计时器超时，最终楼层: {final_floors}")
            self.speak_text(response)
            
            # 清空楼层集合，准备下次收集
            self.floor_arr_set.clear()
        else:
            self.get_logger().info("电梯计时器超时，但未收集到有效楼层")

    def callback(self, msg: String):
        # 如果正在处理请求，则忽略新的请求
        if self.processing:
            self.get_logger().debug("已有请求正在处理中，忽略新请求")
            return
            
        try:
            text = json.loads(msg.data)['text']
            self.get_logger().info(f"原始输入: {text}")
            
            # 检查文本是否有效
            if text and self.is_valid_text(text):
                # 检查模式切换关键词
                self.get_logger().info(f"valid_text:{text}")
                if "电梯模式" in text:
                    # 切换到电梯模式
                    self.flag_chat = 0
                    self.flag_elevator = 1
                    self.get_logger().info("切换到电梯模式")
                    # 只有首次进入电梯模式时才播报
                    if not self.initial_elevator_announced:
                        self.speak_text("电梯模式，请说出您想去的楼层（支持1层到3层）。")
                        self.initial_elevator_announced = True
                    # 重置电梯相关状态
                    self.floor_arr_set.clear()
                    if self.elevator_timer and self.elevator_timer_active:
                        self.elevator_timer.cancel()
                    # 启动初始计时器
                    self.elevator_timer_active = True
                    self.elevator_timer = threading.Timer(self.elevator_timespan, self._handle_elevator_timeout)
                    self.elevator_timer.start()
                    self.get_logger().info(f"进入电梯模式，启动初始计时器，{self.elevator_timespan}秒后处理")
                    return
                elif "对话模式" in text:
                    # 切换到对话模式
                    self.flag_chat = 1
                    self.flag_elevator = 0
                    self.get_logger().info("切换到对话模式")
                    # 停止电梯计时器
                    if self.elevator_timer and self.elevator_timer_active:
                        self.elevator_timer.cancel()
                        self.elevator_timer_active = False
                    # 清空电梯状态
                    self.floor_arr_set.clear()
                    # 只有首次进入对话模式时才播报
                    if not self.initial_chat_announced:
                        self.speak_text("对话模式，请提问。")
                        self.initial_chat_announced = True
                    return
                
                # 根据当前模式处理文本
                if self.flag_chat == 1:  # 对话模式
                    self.get_logger().info(f"对话模式 - 有效输入: {text}")
                    
                    # 标记为正在处理
                    self.processing = True
                    text_ans=text
                    # 获取回答
                    if self.use_ollama_llm:
                        text_ans = chat_with_ollama(text)
                    # self.get_logger().info(f"回答: {text_ans}")
                    
                    # 使用TTS播放回答
                    if self.speak_text(text_ans):
                        self.get_logger().info("已通过TTS播放回答")
                    else:
                        self.get_logger().error("TTS播放失败")
                    
                    # 处理完成
                    self.processing = False
                    
                elif self.flag_elevator == 1:  # 电梯模式
                    self.get_logger().info(f"电梯模式 - 解析楼层: {text}")
                    
                    # 调用parse_floors解析楼层，使用默认参数
                    floor_arr = parse_floors(text, min_floor=self.default_min_floor, max_floor=self.default_max_floor)
                    if len(floor_arr) > 0:
                        self.speak_text("好的")
                        self.get_logger().info(f"floor_arr:{floor_arr}")
                        
                    
                    # 无论解析结果如何，都要重置计时器（包括无效楼层的情况）
                    if self.elevator_timer and self.elevator_timer_active:
                        self.elevator_timer.cancel()
                        self.get_logger().info("重置电梯计时器")
                    
                    # 只有在范围内的楼层才添加到集合中
                    if floor_arr:  # floor_arr不为空，表示有范围内的楼层
                        # 将有效楼层添加到去重集合中
                        for floor in floor_arr:
                            self.floor_arr_set.add(floor)
                        
                        self.get_logger().info(f"当前楼层集合: {sorted(self.floor_arr_set)}")

                    
                    # 重新启动计时器（无论解析结果如何）
                    self.elevator_timer_active = True
                    self.elevator_timer = threading.Timer(self.elevator_timespan, self._handle_elevator_timeout)
                    self.elevator_timer.start()
                    self.get_logger().info(f"重新启动电梯计时器，{self.elevator_timespan}秒后处理")
            else:
                self.get_logger().info("输入被过滤：不是有效的中文或英文内容")
                
        except (json.JSONDecodeError, KeyError):
            pass

def main():
    # 获取命令行参数中的网络接口名称和默认模式
    network_interface = 'eth0'
    default_mode = 'chat'  # 默认为对话模式
    
    if len(sys.argv) > 1:
        network_interface = sys.argv[1]
    if len(sys.argv) > 2:
        if sys.argv[2] in ['chat', 'elevator']:
            default_mode = sys.argv[2]
        else:
            print(f"警告: 无效的默认模式 '{sys.argv[2]}'，使用默认值 'chat'")
    
    print(f"使用网络接口: {network_interface}")
    print(f"默认模式: {default_mode}")
    print("启动ASR-TTS对话系统...")
    print("提示: 本程序使用子进程方式执行TTS，避免与ROS2冲突")
    print("用法: python3 new_asr_topic.py [network_interface] [default_mode]")
    print("      default_mode: 'chat' (对话模式) 或 'elevator' (电梯模式)")
    
    # 初始化 ROS2
    try:
        rclpy.init()
        
        # 创建节点
        node = TextPrinter(network_interface, default_mode)
        print("节点创建成功，等待语音输入...")
        
        # 运行节点
        rclpy.spin(node)
    except KeyboardInterrupt:
        print("程序被用户中断")
    except Exception as e:
        print(f"发生错误: {str(e)}")
        import traceback
        traceback.print_exc()
    finally:
        # 清理资源
        try:
            if 'node' in locals() and node is not None:
                node.destroy_node()
        except Exception as e:
            print(f"清理节点时出错: {str(e)}")
            
        try:
            rclpy.shutdown()
        except Exception as e:
            print(f"关闭ROS2时出错: {str(e)}")
            
        print("程序已退出")

if __name__ == '__main__':
    main()